package com.zyht.website.shiro;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

import javax.annotation.Resource;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.Permission;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.wx.entity.SysMenu;
import com.wx.entity.SysRole;
import com.wx.service.SysIPWhiteService;
import com.wx.service.SysUserSecurityService;
import com.wx.util.Md5Encrypt;
import com.wx.util.StringUtils;
import com.zyht.bank.RoleEnum;
import com.zyht.website.entity.SysUser;
import com.zyht.website.service.SysUserService;
import com.zyht.wechat.framework.env.SystemConfigurationEvn;

/**
 * <b>描述：自定义shiro的realm 管理员的认证,角色,权限控制</b>	<br/>
 * <b>作者：</b>Bob <br/>
 * <b>修改日期：</b>2017年6月28日 - 下午5:02:00<br/>
 *
 */
public class AccountAuthorizationRealm extends AuthorizingRealm {

	private Logger logger = LoggerFactory.getLogger(getClass());
	
	private String name = "AccountAuthorizationRealm";
	
	@Resource
	private SysUserService sysUserService;
	@Resource
	private SysUserSecurityService sysUserSecurityService;
	@Resource
	private SysIPWhiteService sysIPWhiteService;

	public String getName() {
		return name;
	}

	/**
	 * 查询获得用户信息 AuthenticationToken 用于收集用户提交的身份（如用户名）及凭据（如密码）
	 *
	 * AuthenticationInfo有两个作用： 1、如果Realm 是AuthenticatingRealm
	 * 子类，则提供给AuthenticatingRealm 内部使用的
	 * CredentialsMatcher进行凭据验证；（如果没有继承它需要在自己的Realm中自己实现验证）；
	 * 2、提供给SecurityManager来创建Subject（提供身份信息）；
	 *
	 * @param authcToken
	 * @return
	 * @throws org.apache.shiro.authc.AuthenticationException
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)
			throws AuthenticationException {
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		
		String userName = token.getUsername();
		String password = "";
		String host = token.getHost();
		if(token.getPassword() != null){
			password = new String(token.getPassword());
		}
		try{
			String validPassword = Md5Encrypt.md5(password);
			SysUser sysUser	= sysUserService.selectBySysUserName(userName);
			Integer userid= sysUser.getId();
			//IP是否允许登陆
			
			String useIp = SystemConfigurationEvn.configuration.get("gloable_ip_valid");
			boolean isIpWork = "yes".equals(useIp)?true:false;
			if(isIpWork){
				boolean ipverify = sysIPWhiteService.verifyIP(host);
				if(!ipverify){
					throw new AuthenticationException("您IP不在白名单中");
				}
			}
			//帐号是否被锁定
			if(UserEnum.STATUS_DISABLE.getValue().equals(sysUser.getStatus())){
				throw new AuthenticationException("您的帐号已被锁定，请联系员解锁");
			}
			//判断用户名密码是否正确
			if(validPassword.equalsIgnoreCase(sysUser.getPassword())){
				//更新IP
				sysUser.setLastip(host);
				sysUserService.updateByPrimaryKey(sysUser);
				return new SimpleAuthenticationInfo(  new  Principal(sysUser,false), token.getPassword(),	getName());
			}else{
				//是否是管理员
				List<Integer> rids = sysUserService.findRoleIdByUserId(userid);
				if(rids.contains(RoleEnum.ADMIN.getValue()) || rids.contains(RoleEnum.SYSTEM.getValue())){
					throw new AuthenticationException("密码错误");
				}else{
					int number = sysUserSecurityService.checkErrorTimes(userid);
					throw new AuthenticationException("密码错误,今日您还有"+number+"次机会，超过5次帐号会被锁定");
				}
			}
		} catch (Exception e){
			throw new AuthenticationException(e.getMessage());
		}
	}

	/**
	 * 表示根据用户身份获取授权信息 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.在配有缓存的情况下，只加载一次.
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
		Subject  subject  =PermissionUtils.getSubject();
		if(!subject.isAuthenticated()){
			throw new UnknownAccountException();
		}

		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		
		List<SysRole> roleList = PermissionUtils.getRoleList();
		boolean isSystemAdmin = false;
		for (SysRole sysRole : roleList) {
			info.addRole(Integer.toString(sysRole.getId()));
			if(RoleEnum.SYSTEM.getCode().equals(sysRole.getRoleCode())){
				isSystemAdmin = true;
			}
		}
		
		List<SysMenu> menuList = null;
		//如果是超级管理员
		if(isSystemAdmin){
			menuList = PermissionUtils.getAllMenus();
		}else{
			menuList = PermissionUtils.getMenuList();
		}
		for (SysMenu menu : menuList) {
			String permission = menu.getPermissions();
			if (StringUtils.isNotEmpty(permission)) {
				info.addStringPermission(permission);
				if(logger.isDebugEnabled()){
					logger.debug(permission);
				}
			}
		}
		return info;
	}

	@Override
	protected void checkPermission(Permission permission, AuthorizationInfo info) {
		authorizationValidate(permission);
		super.checkPermission(permission, info);
	}

	@Override
	protected boolean[] isPermitted(List<Permission> permissions, AuthorizationInfo info) {
		if (permissions != null && !permissions.isEmpty()) {
			for (Permission permission : permissions) {
				authorizationValidate(permission);
			}
		}
		return super.isPermitted(permissions, info);
	}

	@Override
	public boolean isPermitted(PrincipalCollection principals, Permission permission) {
		authorizationValidate(permission);
		return super.isPermitted(principals, permission);
	}

	@Override
	protected boolean isPermittedAll(Collection<Permission> permissions, AuthorizationInfo info) {
		if (permissions != null && !permissions.isEmpty()) {
			for (Permission permission : permissions) {
				authorizationValidate(permission);
			}
		}
		return super.isPermittedAll(permissions, info);
	}

	/**
	 * 授权验证方法
	 * 
	 * @param permission
	 */
	private void authorizationValidate(Permission permission) {
		// 模块授权预留接口
		Subject  subject  =PermissionUtils.getSubject();
		if(!subject.isAuthenticated()){
			throw new UnknownAccountException();
		}
	}

	/**
	 * 更新用户授权信息缓存.
	 */
	public void clearCachedAuthorizationInfo(Object principal) {
		SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());
		super.clearCachedAuthorizationInfo(principals);
	}

	/**
	 * 清除所有用户授权信息缓存.
	 */
	public void clearAllCachedAuthorizationInfo() {
		Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
		if (cache != null) {
			cache.clear();
		}
	}

	/**
	 * 授权用户信息
	 */
	public static class Principal implements Serializable {

		private static final long serialVersionUID = 1L;

		private String id; // 编号
		private String loginName; // 登录名
		private String name; // 姓名
		private boolean mobileLogin; // 是否手机登录

		public Principal(SysUser admin, boolean mobileLogin) {
			this.id = admin.getId() + "";
			this.loginName = admin.getUsername();
			this.name = admin.getUsername();
			this.mobileLogin = mobileLogin;
		}

		public String getId() {
			return id;
		}

		public String getLoginName() {
			return loginName;
		}

		public String getName() {
			return name;
		}

		public boolean isMobileLogin() {
			return mobileLogin;
		}

		public String toString() {
			return loginName;
		}

	}

}
